package com.yy.net.socketclass
{
  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.IOErrorEvent;
  import flash.events.ProgressEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.Socket;
  import flash.utils.ByteArray;
  import flash.utils.Endian;
  
  
  public class MySocket extends EventDispatcher{
    
    private var socket:Socket;
    private var packet:ByteArray;						//发送  整包数组
    private var packetlen:uint = 0;                    //发送  整包长
    private var packetbody:ByteArray;                  //发送  包体数组
    
    private var readpacket:ByteArray;                  //收到  包数组
    private var nStatus:int = 0;                       //状态码
    private var nreadPos:int = 0;                      //读包指针
    private var nBodyLen:uint = 0;                     //包体长
	private var enCode:int = 0;                        //命令
    private var ndx:int = 0;							//标识
    // private var m_BufferEncrypt:BufferEncrypt = new BufferEncrypt();
	///////////////////////////////////////////////////////////////////////////////////////////////////////
	/////////////////////////错误类型//////////////////////////////////////////////////////////////////////
    private const REQ_REQUEST:int = 0;                                            // 收包错误
    private const REQ_HEADER:int = 1;                                             // 收包头错误
    private const REQ_BODY:int = 2;                                               // 收包体错误
    private const REQ_DONE:int = 3;                                               // 收包正常
    private const REQ_PROCESS:int = 4;                                            //
    private const REQ_ERROR:int = 5;                                              //　包错
    private const PACKET_HEADER_SIZE:int = 9;									//　包头长
    private const PACKET_BUFFER_SIZE:int = 1024*16;                               //  包最大长度
    
    
    public var host:String;
    public var port:int;
    public var connected:Boolean = false;
    
	
	///////////////
	private var m_SendByteMap:ByteArray = null;//字节映射表
	private var m_RecvByteMap:ByteArray = null;//字节映射表
	///////////////
    public function MySocket(_isSide:Boolean = false, _datatype:String = "String")
	{
    	packet = new ByteArray();
    	packetbody = new ByteArray();
		readpacket = new ByteArray();
//      	readpacket.endian = Endian.BIG_ENDIAN;
		readpacket.endian = Endian.LITTLE_ENDIAN;
//
//    	packet.endian = Endian.BIG_ENDIAN;
		packet.endian = Endian.LITTLE_ENDIAN;
//    	packetbody.endian = Endian.BIG_ENDIAN;
		packetbody.endian = Endian.LITTLE_ENDIAN;
		m_SendByteMap = newLitteEndianByteArray();
		m_RecvByteMap = newLitteEndianByteArray();
    	InitEncrypt(m_SendByteMap, m_RecvByteMap);
    }
	
	/**
	 * 连接状态
	 */
    public function getConnecState():Boolean
	{
		return connected;
	}
    /**
     * 连接
     */
    public function connect(_host:String, _port:int):void
	{
		
		host = _host;
		port = _port;
		  
		if (connected)
		{
			return;
		}
		trace("连接请求:" + host + "连接端口:" + port);
		socket = new Socket();
		socket.endian = Endian.BIG_ENDIAN; //必须设置 网络包序的问题 :低位在前
		socket.connect(host,port);
		reset();
		socket.addEventListener(IOErrorEvent.IO_ERROR,errorFun);
		socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityerrfun);
		socket.addEventListener(Event.CONNECT, connectFun);		
    }
    /**
     * 写开头
     */
    public function writeBegin(cmd:int, cVer:int=0, cSubVer:int=0):void{
		cVer = COMMANDTYPE.SERVER_PACKET_VER;
		cSubVer = COMMANDTYPE.SERVER_SUBPACKET_VER;
   		packetlen = 0;
   		packet.position = 0;
   		packet.length = 0;
   		packetbody.position = 0;
   		packetbody.length = 0;
    	packet.writeMultiByte("IC","utf-8");
    	packet.writeShort(cmd);
    	packet.writeByte(cVer);
    	packet.writeByte(cSubVer);
    }
	/**
	 * 写结尾
	 */
    public function writeEnd():void{
    	//packet.position = 6;
    	packet.writeShort(packetlen);
		packet.writeByte(0);
    	packet.writeBytes(packetbody, 0, packetlen);
    }
	
	/**
	 * 写位码
	 */
	public function writeCode(val:int):void {
		packet.position = 8;
		packet.writeByte(val);
	}
	
	/**
	 * 写整型
	 */
    public function writeInt(val:int):void{
    	packetlen += 4;
    	packetbody.writeInt(val);
    }
	
	/**
	 *写一个Number 
	 * @param numb
	 * 
	 */
	public function writeDouble(numb:Number):void {
		packetlen += 8;
		packetbody.writeDouble(numb);
	}
	
	/**
	 * 写无符号整型
	 */
    public function writeUint(val:uint):void{
    	packetlen += 4;
    	packetbody.writeUnsignedInt(val);
    }
	
	/**
	 * 写短整型
	 */
    public function writeShort(val:int):void{
    	packetlen += 2;
    	packetbody.writeShort(val);
		
	}
	
	/**
	 * 写字节
	 */
	public function writeByte(val:int):void
	{
		packetlen += 1;
		packetbody.writeByte(val);
	}
	
	/**
	 * 写字符
	 */
    public function writeString(val:String):void{
    	var stringbody:ByteArray = new ByteArray();
    	//stringbody.writeMultiByte(val, "gb2312");
    	stringbody.writeMultiByte(val, "utf-8");
		packetbody.writeShort(stringbody.length);
        packetlen += 2;
    	packetbody.writeBytes(stringbody);
    	packetlen += stringbody.length;
		stringbody = null;
    }
	
    /**
     * 读
     */
    private function reset():void{
    	nStatus = REQ_REQUEST;
    	nreadPos = 0;
    	nBodyLen = 0;
    	readpacket.position = 0;
    	readpacket.length = 0;
    }
    /**
     * 读头
     */
    private function read_header(len:int):Boolean
	{
		while(nreadPos < PACKET_HEADER_SIZE && ndx < len)
    	{
    		socket.readBytes(readpacket,nreadPos,1);
    		nreadPos++;
    		ndx++;
    	}
    	if(nreadPos < PACKET_HEADER_SIZE)
    		return false;
    	return true;
    }
	/**
	 * 解析
	 */
    private function parse_header():Boolean{
    	var ic:ByteArray = new ByteArray();
    	ic.writeMultiByte("IC", "gb2132");
    	if (readpacket[0] != ic[0] || readpacket[1] != ic[1])
    	{
			ic = null;
    		return false;
    	}
    	ic = null;
    	var ncmd:int = getcmd();
    	if(ncmd <=0 || ncmd >= 32000)
    		return false;
    	nBodyLen = getbodylen();
		enCode = getcode();
    	if (nBodyLen >= 0 && nBodyLen < (PACKET_BUFFER_SIZE - PACKET_HEADER_SIZE))	
		{
    		return true;
		}
trace("收到包头错误");
    	return false;
    }
	
	/**
	 * 解析包体
	 */
    private function parse_body(len:int):Boolean 
	{
    	var nNeed:int = nBodyLen+PACKET_HEADER_SIZE-nreadPos;
		var nBuff:int = len - ndx;
		
    	if(nNeed <= 0)
    		return true;
    	if(nBuff <= 0)
    		return false;
    	var nCopy:uint = nBuff <  nNeed?nBuff:nNeed;
    	var size:int = readpacket.length + nCopy;
    	if(size > PACKET_BUFFER_SIZE)		
			return false;
		socket.readBytes(readpacket, readpacket.position, nCopy);
    	nreadPos += nCopy;
    	ndx += nCopy;
    	
    	if (nreadPos < (nBodyLen + PACKET_HEADER_SIZE))
		{
			readpacket.position = nreadPos;
    		return false;	
		}
    	return true;
    }
    /**
     * 读命令
     */
    public function getcmd():int{
    	readpacket.position = 2;
    	return readpacket.readShort();
    }
	
	/**
	 * 读版本
	 */
    public function getver():int{
    	readpacket.position = 4;
    	return readpacket.readByte();
    }
	
	/**
	 * 读副版本
	 */
    public function getsubver():int{
    	readpacket.position = 5;
    	return readpacket.readByte();
    }
	/**
	 * 读包长
	 */
    public function getbodylen():int{
    	readpacket.position = 6;
    	return readpacket.readShort();
    }
	/**
	 * 
	 */
    public function getcode():int {
		readpacket.position = 8;
		return readpacket.readByte();
	}
    //读数据
    private var readbodypos:int = PACKET_HEADER_SIZE;
	/**
	 * 读起点
	 */
    public function readbegin():void {
		readpacket.position = 0; 
    	readbodypos = PACKET_HEADER_SIZE;
    }
	/**
	 * 读整型
	 */
    public function readInt():int{
    	readpacket.position =  readbodypos;
    	readbodypos += 4;
		return readpacket.readInt();
    }
	/**
	 *读一个 double 
	 * @return 
	 * 
	 */
	public function readDouble():Number {
		readpacket.position = readbodypos;
		readbodypos += 8;
		return readpacket.readDouble();
	}
	/**
	 * 读无符号整型 
	 */
    public function readUint():uint{
    	readpacket.position =  readbodypos;
    	readbodypos += 4;
		return readpacket.readUnsignedInt();
    }
	/**
	 * 读短整型 
	 */
    public function readShort():int{
    	readpacket.position =  readbodypos;
    	readbodypos += 2;
		return readpacket.readShort();
    }
	/**
	 * 读字节
	 */
	public function readByte():int{
		readpacket.position = readbodypos;
		readbodypos += 1;
		return readpacket.readByte();
	}
    /**
     * 读字符
     */
    public function readString():String
    {
	
    	readpacket.position =  readbodypos;
    	readbodypos += 2;
    	var len:uint = readpacket.readShort();
		readpacket.position = readbodypos;
    	readbodypos += len;
		return readpacket.readMultiByte(len, "utf-8");
    }
	
	/**
	 * 读中文字符
	 */
	public function readgb2132String():String
	{
		readpacket.position =  readbodypos;
    	readbodypos += 2;
    	var len:uint = readpacket.readShort();
    	readpacket.position =  readbodypos;
    	readbodypos += len;
		return readpacket.readMultiByte(len, "gb2132");
	}
    /**
     * 发送往后台
     */
    public function sendcmd():void
    {
		trace("发送信息了"+connected);
		if (connected)
		{
			//加密
			var code:int = EncryptBuffer(packet, PACKET_HEADER_SIZE, packet.length, m_SendByteMap);
			this.writeCode(code);
			socket.writeBytes(packet, 0, packetlen+PACKET_HEADER_SIZE);
			socket.flush();
		}
    }
    /**
     * 断开
     */
    public function close():void
	{
	  trace("手动关闭");
      clearEvent();
	  if (connected)
	  {
		connected = false;
		socket.close();
		socket = null;
	  }
    }
    
    /**
     * 连接事件
     */
    private function connectFun(e:Event):void
	{
      connected = true;
	  trace('********连成，********' + connected);
      clearEvent();
      socket.addEventListener(ProgressEvent.SOCKET_DATA,socketDataFun);
      socket.addEventListener(Event.CLOSE,closeFun);
      dispatchEvent(new MySocketEvent(MySocketEvent.CONNECT));
    }
    
    /**
     * 关闭事件
     */
    private function closeFun(e:Event):void{
		connected = false;
//		throw new Error("连接关闭");
		trace("连接关闭");
		dispatchEvent(new MySocketEvent(MySocketEvent.CLOSE));
    }
    
    private function securityerrfun(e:SecurityErrorEvent):void
	{
		trace("安全策略出错");
    	dispatchEvent(new MySocketEvent(MySocketEvent.SECURITYERROR));
		close();
    }
    /**
	* 失败事件
	*/
    private function errorFun(e:IOErrorEvent):void
	{
		close();
		trace("连接出错"+e.text);
		dispatchEvent(new MySocketEvent(MySocketEvent.ERROR));
    }
    
    /**
     * 接收事件
     */
    private function socketDataFun(e:ProgressEvent):void
	{
      ndx = 0;
      var len:int = socket.bytesAvailable;
      while(ndx < len && nStatus != REQ_ERROR)
      {
			switch(nStatus)
			{
			case REQ_REQUEST:
			case REQ_HEADER:
				if(!read_header(len)){
					break;
				}
				if(!parse_header()){
					nStatus = REQ_ERROR;
					break;
				}else
					nStatus = REQ_BODY;
			case REQ_BODY:
				if(parse_body(len))
					nStatus = REQ_DONE;
				break;
			default:
				return ;
			}
			if(nStatus == REQ_ERROR){
trace("头解析错误");
				return ;
			}
			if(nStatus == REQ_DONE)
			{
				//CrevasseBuffer(readpacket, PACKET_HEADER_SIZE, readpacket.length, enCode, m_RecvByteMap
				//效验包
				
				CrevasseBuffer(readpacket, PACKET_HEADER_SIZE, readpacket.length, enCode, m_RecvByteMap);
				var eve:MySocketEvent = new MySocketEvent(MySocketEvent.SYNC);

				dispatchEvent(eve);
				eve = null;
				reset();
			}
		  }
		  return ;
     
    }
    
    /**
     * 清理事件侦听
     */
    private function clearEvent():void
	{
      if (socket != null)
	  {
        if(socket.hasEventListener(IOErrorEvent.IO_ERROR)) socket.removeEventListener(IOErrorEvent.IO_ERROR,errorFun);
        if(socket.hasEventListener(Event.CONNECT)) socket.removeEventListener(Event.CONNECT,connectFun);
        if(socket.hasEventListener(ProgressEvent.SOCKET_DATA)) socket.removeEventListener(ProgressEvent.SOCKET_DATA,socketDataFun);
        if(socket.hasEventListener(Event.CLOSE)) socket.removeEventListener(Event.CLOSE,closeFun);
        if(socket.hasEventListener(SecurityErrorEvent.SECURITY_ERROR)) socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,securityerrfun);
      }
    }
  }
}
include "BufferEncrypt.as"